package com.berchen.算法;

import java.util.Arrays;

/**
 * 堆排序  树的实际应用
 * 思路：
 * 1、将数据构建成一个大顶堆或者小顶堆，
 * 2、将数的根节点拿出来 放入新数组
 * 3、将剩下元素继续构建顶堆 重复上面操作
 * <p>
 * 如何构建大顶堆？
 * 找到非最后一个非叶子节点  然后将该节点与该节点的两子节点进行比较 将比较大的值放入该节点
 * 找到非最后第二个叶子节点 。。。。
 * 重复上面的操作
 */
public class HeapTreeSort {

    public static void main(String[] args) {

        int arr[] = {4, 6, 8, 5, 9};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 堆排序
     *
     * @param arr
     */
    public static void heapSort(int[] arr) {

        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            createHeap(arr, i, arr.length);
        }
        for (int j = arr.length - 1; j > 0; j--) {
            // 交换
            arr[0] = arr[0] + arr[j];
            arr[j] = arr[0] - arr[j];
            arr[0] = arr[0] - arr[j];
            createHeap(arr, 0, j);
        }
    }

    /**
     * 构建大顶堆
     * 完成将以为index对应的非叶子节点的树调整为大顶堆
     *
     * @param arr    数组 带调整的数组 就是一个二叉树
     * @param index  表示非叶子节点在数组中的索引
     * @param length 对数组中多少个元素进行调整 length是在逐渐减少
     */
    public static void createHeap(int[] arr, int index, int length) {

        // 先取出当前元素的值，保存在这
        int temp = arr[index];

        // 1、 k=2*index+1 是index节点的左子节点
        for (int k = index * 2 + 1; k < length; k = k * 2 + 1) {
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;    // 指向右子节点
            }
            // 如果子节点大于父节点
            if (arr[k] > temp) {
                arr[index] = arr[k];// 把较大的值赋值给当前节点
                index = k;// index指向k 继续循环比较
            } else {
                break;
            }
        }
        // 当for循环结束后，我们已经将以index为父节点的树的最大值放在了最顶端
        arr[index] = temp;    //将temp 值放到调整后的位置
    }
}
